package com.itfreer.bpm.activiti.workflow;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.activiti.bpmn.model.BpmnModel;
import org.activiti.bpmn.model.ExclusiveGateway;
import org.activiti.bpmn.model.FlowElement;
import org.activiti.bpmn.model.InclusiveGateway;
import org.activiti.bpmn.model.ParallelGateway;
import org.activiti.bpmn.model.SequenceFlow;
import org.activiti.bpmn.model.UserTask;
import org.activiti.engine.HistoryService;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.impl.RepositoryServiceImpl;
import org.activiti.engine.impl.persistence.entity.ExecutionEntity;
import org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntity;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.runtime.Execution;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.itfreer.bpm.activiti.workflow.notaskflow.JumpCmd;
import com.itfreer.bpm.option.para.NextTaskInfo;
import com.itfreer.bpm.option.para.NextTaskType;
import com.itfreer.bpm.option.para.TaskInfo;
import com.itfreer.bpm.option.para.TaskType;
import com.itfreer.bpm.power.para.UserInfo;
import com.itfreer.bpm.stringutils.StringUtils;
import com.itfreer.bpm.workflow.drive.IWorkFlowDrive;

/**
 * activiti流程驱动类
 * @author gj
 *
 */
@Component
public class ActivitiWorkFlowDrive implements IWorkFlowDrive{
	
	/**
	 * 运行时服务
	 */
	@Autowired(required = false)
	private RuntimeService runtimeService;
	
	/**
	 * 流程任务服务
	 */
	@Autowired(required = false)
	protected TaskService taskService;
	
	/**
	 * 流程历史服务
	 */
	@Autowired(required = false)
	protected HistoryService historyService;	
	
	/**
	 * 流程部署服务
	 */
	@Autowired(required = false)
	protected RepositoryService repositoryService;
	
	/**
	 * activiti 6.0 任意节点跳转实现
	 */
	@Autowired(required = false)
	protected JumpCmd jumpCmd;
	/**
	 * 启动流程
	 */
	@Override
	public String startFlow(String activitiKey) {
		// 启动流程
		Map<String, Object> variables = new HashMap<String, Object>();
		ProcessInstance processInstance = runtimeService
				.startProcessInstanceByKey(activitiKey, variables);
		String exeId = processInstance.getId();
		//TODO 异常暂时没有处理
		if(exeId==null || "".equals(exeId.trim())) {
			throw new RuntimeException("流程启动失败");
		}
		return exeId;
	}
	/**
	 * 查询当前环节
	 * @param sexeid
	 */
	@Override
	public List<TaskInfo> getCurrentTask(String sexeid) {
		List<Task> listTasks = taskService.createTaskQuery()
				.processInstanceId(sexeid).active().list();
		
		if(listTasks!=null) {
			List<TaskInfo> userTasks=new ArrayList<TaskInfo>();
			for(Task actTask:listTasks) {
				TaskInfo userTask=new TaskInfo();
				userTask.setTaskdefinedid(actTask.getTaskDefinitionKey());
				userTask.setTaskName(actTask.getName());
				userTasks.add(userTask);
			}
			return userTasks;
		}
		return null;
	}
	
	/**
	 * 简单的项目任务完成
	 * @return
	 */
	@Override
	public boolean SignCommonTask(String proId,UserInfo user,TaskInfo tjTask,HashMap<String, Object>ComValue) {
		List<Task> listTasks = taskService.createTaskQuery()
				.processInstanceId(proId).active().list();
		List<String> tempcountersignUsers = new ArrayList<String>();
		Task task=null;
		if(listTasks!=null && listTasks.size()>0) {
			for(Task itask :listTasks) {
				if(itask.getTaskDefinitionKey().equals(tjTask.getTaskdefinedid()))task=itask;
			}
		}
		tempcountersignUsers.add(user.getUserId());
		ComValue.put("countersignUsers", tempcountersignUsers);
		runtimeService.setVariable(task.getExecutionId(),"counter", tempcountersignUsers.size());
		runtimeService.setVariable(task.getExecutionId(), "currentSign", 0);
	
		// 设置任务的执行人
		taskService.setAssignee(task.getId(), user.getUserId());
		// 领取第一个任务
		taskService.claim(task.getId(), user.getUserId());
		//HashMap<String,Object> comMap = new HashMap<String,Object>();
		
		HashMap<String, Object>param=new HashMap<String, Object>();
		this.setTaskExpression(param, task);
		if(ComValue!=null && ComValue.size()>0) {
			param.putAll(ComValue);
		}
		// 完成任务
		taskService.complete(task.getId(), param);
		return true;
	}
	
	/**
	 * 
	 * @param ComValue
	 * @param task
	 */
	public void setTaskExpression(HashMap<String, Object>ComValue,Task task) {
		  BpmnModel model = repositoryService.getBpmnModel(task.getProcessDefinitionId());
	        if(model!=null) {
	        	Collection<FlowElement> flowElements = model.getMainProcess().getFlowElements();
	            for(FlowElement e : flowElements) {
	                System.out.println("flowelement id:" + e.getId() + "  name:" + e.getName() + "   class:" + e.getClass().toString());
	                
	                if(e.getClass().toString().trim().toLowerCase().endsWith("org.activiti.bpmn.model.usertask")
	                		&& task.getTaskDefinitionKey().equals(e.getId())) {
	                	UserTask utask=(UserTask)e;
	                	List<SequenceFlow> outgoing=utask.getOutgoingFlows();
	                	if(outgoing!=null && outgoing.size()>0) {
	                		for(SequenceFlow flow:outgoing) {
	                        	String condition_temp=
	                        			flow.getConditionExpression();
	                        	if(condition_temp!=null && !"".equals(condition_temp.trim())) {
	                        		String[] spl=condition_temp.split("==");
	                        		String tempkey=spl[0].replace("${", "");
	                        		ComValue.put(tempkey, null);
	                        	}
	                        	this.setFlowExpression(ComValue, flow);
	                    	}
	                	}
	                }
	            }
	        }
			return ;
	}
	
	/**
	 * 构建流程驱动参数
	 * @param ComValue
	 * @param flow
	 */
	public void setFlowExpression(HashMap<String, Object>ComValue,SequenceFlow flow) {
		FlowElement targetElement=flow.getTargetFlowElement();
		if(targetElement.getClass().toString().trim().
				toLowerCase().endsWith("org.activiti.bpmn.model.usertask")) {
			return;
		//选择网关
		}else if(targetElement.getClass().toString().trim().
				toLowerCase().endsWith("org.activiti.bpmn.model.exclusivegateway")) {
			
			ExclusiveGateway gateway=(ExclusiveGateway)targetElement;
			List<SequenceFlow> outgoing=gateway.getOutgoingFlows();
			if(outgoing!=null && outgoing.size()>0) {
				for(SequenceFlow iflow:outgoing) {
	            	String condition_temp=
	            			iflow.getConditionExpression();
	            	if(condition_temp!=null && !"".equals(condition_temp.trim())) {
                		String[] spl=condition_temp.split("==");
                		String tempkey=spl[0].replace("${", "");
                		ComValue.put(tempkey, null);
                	}
	            	this.setFlowExpression(ComValue, iflow);
	        	}
			}
		//选择平行网关
		}else if(targetElement.getClass().toString().trim().
				toLowerCase().endsWith("org.activiti.bpmn.model.inclusivegateway")) {
			InclusiveGateway gateway=(InclusiveGateway) targetElement;
			List<SequenceFlow> outgoing=gateway.getOutgoingFlows();
			if(outgoing!=null && outgoing.size()>0) {
				for(SequenceFlow iflow:outgoing) {
					String condition_temp=
	            			iflow.getConditionExpression();
					if(condition_temp!=null && !"".equals(condition_temp.trim())) {
                		String[] spl=condition_temp.split("==");
                		String tempkey=spl[0].replace("${", "");
                		ComValue.put(tempkey, null);
                	}
					this.setFlowExpression(ComValue, iflow);
	        	}
			}
		
		//同步平行网关
		}else if(targetElement.getClass().toString().trim().
				toLowerCase().endsWith("org.activiti.bpmn.model.parallelgateway")) {
			ParallelGateway gateway=(ParallelGateway) targetElement;
			List<SequenceFlow> outgoing=gateway.getOutgoingFlows();
			if(outgoing!=null && outgoing.size()>0) {
				for(SequenceFlow iflow:outgoing) {
					String condition_temp=
	            			iflow.getConditionExpression();
					if(condition_temp!=null && !"".equals(condition_temp.trim())) {
                		String[] spl=condition_temp.split("==");
                		String tempkey=spl[0].replace("${", "");
                		ComValue.put(tempkey, null);
                	}
	        	}
			}
			
		}
	}
	
	
	
	/**  
	 * <p>
	 * TODO
	 * </p>
	* @param comValues
	* @param comMap
	*/
	private void filterComValues(Map<String, Object> comValues, HashMap<String, Object> comMap) {
		Set<String> keySet = comValues.keySet();
		for (String key_ : keySet) {
			if(comValues.get(key_) instanceof String){
				String value_ = (String)comValues.get(key_);
				if(!StringUtils.IsNullOrEmpty(value_) && value_.length()>100){
					comMap.put(key_, StringUtils.textCut(value_, 100, "..."));
				}else{
					comMap.put(key_, comValues.get(key_));
				}
			}else{
				comMap.put(key_, comValues.get(key_));
			}
		}
	}
	
	/**
	 * 解析退回节点问题
	 * 1、第一步获取当前环节的id，然后获取下一个节点，只有当下一个节点的是usertask时，且条件是退回时，才是退回节点，如果是其他网关，只有条件为空时，才直接往下走
	 * @param bpmkey
	 * @param taskid
	 * @param condition
	 * @return
	 */
	public NextTaskInfo getRollBackTask(String bpmkey,String taskid){
		ProcessDefinition processDefinition = repositoryService
				.createProcessDefinitionQuery()
				.processDefinitionKey(bpmkey).latestVersion()
				.singleResult();
		NextTaskInfo nextTaskInfo=new NextTaskInfo();
        BpmnModel model = repositoryService.getBpmnModel(processDefinition.getId());
        if(model!=null) {
        	Collection<FlowElement> flowElements = model.getMainProcess().getFlowElements();
            for(FlowElement e : flowElements) {
                System.out.println("flowelement id:" + e.getId() + "  name:" + e.getName() + "   class:" + e.getClass().toString());
                //1、第一步解析流程，获取的当前环节
                if(e.getClass().toString().trim().toLowerCase().endsWith("org.activiti.bpmn.model.usertask")
                		&& taskid.equals(e.getId())) {
                	UserTask task=(UserTask)e;
                	//2、获取流程走向的下一个节点
                	List<SequenceFlow> outgoing=task.getOutgoingFlows();
                	if(outgoing!=null && outgoing.size()>0) {
                		for(SequenceFlow flow:outgoing) {
                        	
                			String tempCondition=flow.getConditionExpression();
                			if(this.strIsNullOrEmpty(tempCondition) || tempCondition.contains("退回")) {
                				//3、只有下一个流程节点为选择网关时，才能进行退回选择
                            	FlowElement targetElement=flow.getTargetFlowElement();
                            	if(targetElement.getClass().toString().trim().
                    					toLowerCase().endsWith("org.activiti.bpmn.model.exclusivegateway")) {
                            		ExclusiveGateway gateway=(ExclusiveGateway)targetElement;
                    				List<SequenceFlow> exclusivegateway_outgoing=gateway.getOutgoingFlows();
                    				
                    				if(exclusivegateway_outgoing!=null && exclusivegateway_outgoing.size()>0) {
                    					for(SequenceFlow iflow:exclusivegateway_outgoing) {
                    						String exclusivegateway_condition=iflow.getConditionExpression();
                    						if(!this.strIsNullOrEmpty(exclusivegateway_condition)
                    								&& exclusivegateway_condition.contains("退回")) {
                    							this.findNextUserTask(nextTaskInfo, iflow, null);
                    						}
                    		        	}
                    				}
                            	}
                			}
                    	}
                	}
                }
            }
        }
		return nextTaskInfo;
	}
	
	/**
	 * 判断字符串是不是空值或者""
	 * @param str
	 * @return
	 */
	private boolean strIsNullOrEmpty(String str) {
		if(str==null || "".equals(str.trim())) return true;
		else return false;
	}

	/**
	 * 
	 */
	@Override
	public NextTaskInfo getNextTask(String bpmkey,String taskid){
		ProcessDefinition processDefinition = repositoryService
				.createProcessDefinitionQuery()
				.processDefinitionKey(bpmkey).latestVersion()
				.singleResult();
		String condition="提交";
		NextTaskInfo nextTaskInfo=new NextTaskInfo();
        BpmnModel model = repositoryService.getBpmnModel(processDefinition.getId());
        if(model!=null) {
        	Collection<FlowElement> flowElements = model.getMainProcess().getFlowElements();
            for(FlowElement e : flowElements) {
                System.out.println("flowelement id:" + e.getId() + "  name:" + e.getName() + "   class:" + e.getClass().toString());
                
                if(e.getClass().toString().trim().toLowerCase().endsWith("org.activiti.bpmn.model.usertask")
                		&& taskid.equals(e.getId())) {
                	UserTask task=(UserTask)e;
                	List<SequenceFlow> outgoing=task.getOutgoingFlows();
                	if(outgoing!=null && outgoing.size()>0) {
                		for(SequenceFlow flow:outgoing) {
                        	String condition_temp=
                        			flow.getConditionExpression();
                        	if((condition==null || "".equals(condition)) || (condition_temp==null || "".equals(condition_temp.trim()))) {
                        		findNextUserTask(nextTaskInfo, flow,condition);
                        	}else if(condition!=null && condition_temp!=null 
                        			&& (condition.trim().equals(condition_temp.trim())
                        					|| condition_temp.contains(condition)
                        					|| condition.contains(condition_temp))){
                        		findNextUserTask(nextTaskInfo, flow,condition);
                        	}
                    	}
                	}
                	
                }
            }
        }
        
      //下一个环节只有一个环节，统一为普通提交节点
  		if(nextTaskInfo.getNextTask()!=null && nextTaskInfo.getNextTask().size()<2 && nextTaskInfo.getNextTask().size()>0) {
  			if(nextTaskInfo.getNextTask().get(0).getTaskType().equals(TaskType.MultiTask)) {
  				nextTaskInfo.setNextTaskType(NextTaskType.MultiSingleTask);	
  			}else {
  				nextTaskInfo.setNextTaskType(NextTaskType.CommonTask);	
  			}
  		}
  		
  		if(nextTaskInfo.getNextTask()==null || nextTaskInfo.getNextTask().size()<1) {
  			//TODO 下一个环节没有节点信息
  			System.out.println("流程结束");
  		}
  		return nextTaskInfo;
	}
	
	/**
	 * 获取流程节点类型
	 * @param bpmKey
	 * @param taskid
	 * @return
	 */
	@Override
	public String getTaskStringType(String bpmKey,String taskid) {
		ProcessDefinition processDefinition = repositoryService
				.createProcessDefinitionQuery()
				.processDefinitionKey(bpmKey).latestVersion()
				.singleResult();
        BpmnModel model = repositoryService.getBpmnModel(processDefinition.getId());
        if(model!=null) {
        	Collection<FlowElement> flowElements = model.getMainProcess().getFlowElements();
            for(FlowElement e : flowElements) {
                System.out.println("flowelement id:" + e.getId() + "  name:" + e.getName() + "   class:" + e.getClass().toString());
                
                if(e.getClass().toString().trim().toLowerCase().endsWith("org.activiti.bpmn.model.usertask")
                		&& taskid.equals(e.getId())) {
                	UserTask task=(UserTask)e;
                	String task_assigness=task.getAssignee();
        			if("${countersignUser}".equals(task_assigness) || "${countersignUsers}".equals(task_assigness)){
        				return TaskType.MultiTask.toString();
        			}else {
        				return TaskType.CommonTask.toString();
        			}
                }
            }
        }
		return null;
	}

	private void findNextUserTask(NextTaskInfo nextTaskInfo, SequenceFlow flow,String condition) {
		FlowElement targetElement=flow.getTargetFlowElement();
		if(targetElement.getClass().toString().trim().
				toLowerCase().endsWith("org.activiti.bpmn.model.usertask")) {
			UserTask targettask=(UserTask)targetElement;
			String task_assigness=targettask.getAssignee();
		 	TaskInfo taskinfo=new TaskInfo();
			taskinfo.setTaskdefinedid(targettask.getId());
			taskinfo.setTaskName(targettask.getName());
			if(task_assigness!=null && "${countersignUser}".equals(task_assigness.trim())) {
				taskinfo.setTaskType(TaskType.MultiTask);
			}else{
				taskinfo.setTaskType(TaskType.CommonTask);
			}
			nextTaskInfo.getNextTask().add(taskinfo);
		//选择网关
		}else if(targetElement.getClass().toString().trim().
				toLowerCase().endsWith("org.activiti.bpmn.model.exclusivegateway")) {
			nextTaskInfo.setNextTaskType(NextTaskType.ExclusiveTask);
			ExclusiveGateway gateway=(ExclusiveGateway)targetElement;
			List<SequenceFlow> outgoing=gateway.getOutgoingFlows();
			if(outgoing!=null && outgoing.size()>0) {
				for(SequenceFlow iflow:outgoing) {
	            	String condition_temp=
	            			iflow.getConditionExpression();
	            	if((condition==null || "".equals(condition)) || (condition_temp==null || "".equals(condition_temp.trim()))) {
	            		findNextUserTask(nextTaskInfo, iflow,condition);
	            	}else if(condition!=null && condition_temp!=null && condition_temp.trim().contains(condition.trim())){
	            		findNextUserTask(nextTaskInfo, iflow,condition);
	            	}
	        	}
			}
		//选择平行网关
		}else if(targetElement.getClass().toString().trim().
				toLowerCase().endsWith("org.activiti.bpmn.model.inclusivegateway")) {
			nextTaskInfo.setNextTaskType(NextTaskType.InclusiveTask);
			InclusiveGateway gateway=(InclusiveGateway) targetElement;
			List<SequenceFlow> outgoing=gateway.getOutgoingFlows();
			if(outgoing!=null && outgoing.size()>0) {
				for(SequenceFlow iflow:outgoing) {
					findNextUserTask(nextTaskInfo, iflow,condition);
	        	}
			}
		
		//同步平行网关
		}else if(targetElement.getClass().toString().trim().
				toLowerCase().endsWith("org.activiti.bpmn.model.parallelgateway")) {
			nextTaskInfo.setNextTaskType(NextTaskType.ParallelTask);
			ParallelGateway gateway=(ParallelGateway) targetElement;
			List<SequenceFlow> outgoing=gateway.getOutgoingFlows();
			if(outgoing!=null && outgoing.size()>0) {
				for(SequenceFlow iflow:outgoing) {
	            	findNextUserTask(nextTaskInfo, iflow,condition);
	        	}
			}
			
		}
	}

	@Override
	public boolean SignMultiSingleTask(String proId, List<UserInfo> users,UserInfo user,TaskInfo tjTask,Map<String, Object> comValues) {
		List<Task> listTasks = taskService.createTaskQuery()
				.processInstanceId(proId).active().list();
		List<String> tempcountersignUsers = new ArrayList<String>();
		Task task=null;
		if(listTasks!=null && listTasks.size()>0) {
			for(Task itask :listTasks) {
				if(itask.getTaskDefinitionKey().equals(tjTask.getTaskdefinedid()))task=itask;
			}
		}
		for(UserInfo iuser:users) {
			tempcountersignUsers.add(iuser.getUserId());
		}
		comValues.put("countersignUsers", tempcountersignUsers);
		runtimeService.setVariable(task.getExecutionId(),"counter", tempcountersignUsers.size());
		runtimeService.setVariable(task.getExecutionId(), "currentSign", 0);
		// 设置任务的执行人
		taskService.setAssignee(task.getId(), user.getUserId());
		// 领取第一个任务
		taskService.claim(task.getId(), user.getUserId());
		
		HashMap<String, Object>param=new HashMap<String, Object>();
		this.setTaskExpression(param, task);
		if(comValues!=null && comValues.size()>0) {
			param.putAll(comValues);
		}
		// 完成任务
		taskService.complete(task.getId(), param);
		return true;
	}
	
	
	/**
	 * 流程节点任意节点跳转
	 */
	@Override
	public boolean JumpTask(String sexeid, String targetTaskDefined) {
		try {
			jumpCmd.jump(sexeid, targetTaskDefined);
			return true;
		}catch(Exception e) {
			return false;
		}
	}
	
	/**
	 * 流程退件（完全退件）
	 * @param exeId
	 * @return
	 */
	@Override
	public boolean dispose(String exeId) {
		// 流程已经结束
		ProcessInstance processInstance = runtimeService
				.createProcessInstanceQuery().processInstanceId(exeId)
				.singleResult();
		if (processInstance == null) {
			return true;
		}

		// 先挂起流程实例
		runtimeService.suspendProcessInstanceById(exeId);
		return true;
	}
	/**
	 * 获取流程的第一个环节
	 */
	@Override
	public TaskInfo getFirstTask(String bpmKey) {
		ProcessDefinition processDefinition = repositoryService
				.createProcessDefinitionQuery()
				.processDefinitionKey(bpmKey).latestVersion()
				.singleResult();

        BpmnModel model = repositoryService.getBpmnModel(processDefinition.getId());
        if(model!=null) {
        	Collection<FlowElement> flowElements = model.getMainProcess().getFlowElements();
            for(FlowElement e : flowElements) {
                System.out.println("flowelement id:" + e.getId() + "  name:" + e.getName() + "   class:" + e.getClass().toString());
                //1、第一步解析流程，获取的当前环节
                if(e.getClass().toString().trim().toLowerCase().endsWith("org.activiti.bpmn.model.usertask")
                		) {
                	UserTask actTask=(UserTask)e;
                	TaskInfo taskInfo=new TaskInfo();
                	taskInfo.setTaskdefinedid(actTask.getId());
                	taskInfo.setTaskName(actTask.getName());
                	return taskInfo;
                }
            }
         }
		return null;
	}

}
